package com.b2b.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.b2b.model.CollectionDto;
import com.b2b.model.GoodsDto;
import com.b2b.model.ShopDto;
import com.b2b.model.StockDto;
import com.b2b.model.entity.goods.Goods;
import com.b2b.model.entity.goods.Model;
import com.b2b.model.entity.goods.Specification;
import com.b2b.model.entity.goods.Stock;
import com.b2b.model.receive.BriefGood;
import com.b2b.model.receive.Good;
import com.b2b.model.receive.GoodsCondition;
import com.b2b.model.receive.GoodsList;
import com.b2b.service.ShopService;
import com.b2b.service.goodsService.*;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

/**
 * 商品工具类
 * @author lsj
 * @date 2021/7/22
 */
@Component
public class GoodsUtil {

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    private final GoodsService goodsService;

    private final SpecificationService specificationService;

    private final ModelService modelService;

    private final StockService stockService;

    private final CategoryUtil categoryUtil;

    private final CollectionService collectionService;

    private final ShopService shopService;

    private final ShopUtil shopUtil;
    @Autowired
    public GoodsUtil(ShopService shopService, CollectionService collectionService, GoodsService goodsService,SpecificationService specificationService,
                     CategoryUtil categoryUtil,ModelService modelService,StockService stockService,
                     ShopUtil shopUtil   ) {
        this.shopService = shopService;
        this.collectionService = collectionService;
        this.goodsService = goodsService;
        this.modelService = modelService;
        this.stockService = stockService;
        this.categoryUtil = categoryUtil;
        this.shopUtil = shopUtil;
        this.specificationService = specificationService;
    }

    public Integer insertAll(GoodsDto goodsDto)throws IOException {
        Goods goods = getGoods(goodsDto);
        goods.setState('0');
        goodsService.insert(goods);
        Integer goodsId = goods.getGoodsId();
        // 取出规格名及规格值Map
        Map<String, List<Object>> goodsSpecificationMap = goodsDto.getGoodsSpecificationMap();
        // 取出规格名list
        List<Specification> specificationList = getSpecification(goodsSpecificationMap,
                goodsId);
        // 插入规格名和规格值
        List<String> modelName = new ArrayList<String>();

        for (Specification specification : specificationList
        ) {
            specificationService.insert(specification);
            Integer specificationId = specification.getSpecificationId();
            List<Model> modelList = getModel(goodsSpecificationMap.get(specification.getSpecificationName()),
                    specificationId);
            for (Model model : modelList
            ) {
                modelService.insert(model);
                modelName.add(model.getModelName());
            }
        }

        List<StockDto> stockList = getStock(goodsDto.getGoodsStockList());
        Double highest = 0.0;
        Double minimum = stockList.get(0).getPrice();
        for (Stock s:stockList
        ) {
            s.setGoodsId(goodsId);
            stockService.insert(s);
            if (s.getPrice() > highest){
                highest = s.getPrice();
            }else if (s.getPrice() < minimum){
                minimum = s.getPrice();
            }
        }
        List<String> attributeList = new ArrayList<String>();
        Map<String, Object> attribute = goodsDto.getGoodsAttributeMap();
        for (Object v : attribute.values()){
            attributeList.add(String.valueOf(v));
        }
        IndexRequest request = new IndexRequest("goods");
        request.timeout(TimeValue.timeValueSeconds(3));
        request.id(""+goodsId);
        char state = '0';
        Good good = new Good();
        good.setGoodsId(goodsId);
        good.setCompanyId(shopUtil.getCompanyId(goodsDto.getShopId()));
        good.setGoodsName(goodsDto.getGoodsName());
        good.setHighest(highest);
        good.setMinimum(minimum);
        good.setShopId(goodsDto.getShopId());
        good.setCategoryId(goodsDto.getCategoryId());
        good.setCategoryName(categoryUtil.getName(goodsDto.getCategoryId()));
        good.setModelName(String.join(",",modelName));
        good.setAttribute(String.join(",",attributeList));
        good.setState(state);
        IndexRequest source = request.source(JSON.toJSONString(good), XContentType.JSON);
        client.index(request, RequestOptions.DEFAULT);

        return goodsId;
    }

    public void deleteAll(Integer goodsId) throws IOException{
        if(goodsId != null) {
            goodsService.deleteByPrimaryKey(goodsId);
            Specification specification = new Specification();
            specification.setGoodsId(goodsId);
            List<Specification> specificationList = specificationService.select(specification);
            Model model = new Model();
            for (Specification s :
                    specificationList) {
                Integer specificationId = s.getSpecificationId();
                specificationService.deleteByPrimaryKey(specificationId);
                model.setSpecificationId(specificationId);
                modelService.delete(model);
            }

            Stock stock = new Stock();
            stock.setGoodsId(goodsId);
            stockService.delete(stock);
            DeleteRequest deleteRequest = new DeleteRequest("goods", ""+goodsId);
            deleteRequest.timeout("3s");
            client.delete(deleteRequest, RequestOptions.DEFAULT);
        }
    }

    public Map<String, List<Object>> getGoodsSpecificationMap(Integer goodsId){
        Specification specification = new Specification();
        specification.setGoodsId(goodsId);
        List<Specification> specificationList = specificationService.select(specification);
        Map<String, List<Object>> goodsSpecificationMap = new HashMap<>();
        for (Specification s:specificationList
        ) {
            Model model = new Model();
            model.setSpecificationId(s.getSpecificationId());
            List<Model> modelList = modelService.select(model);
            List<Object> modelNameList = new ArrayList<>();
            for (Model m:modelList
            ) {
                Object o = m.getModelName();
                modelNameList.add(o);
            }
            goodsSpecificationMap.put(s.getSpecificationName(), modelNameList);
        }
        return goodsSpecificationMap;
    }

//    public GoodsDto getDetail(Integer goodsId, Integer companyId){
    public GoodsDto getDetail(Integer goodsId){
        Goods goods = goodsService.selectByPrimaryKey(goodsId);

        GoodsDto goodsDto = new GoodsDto();

        boolean isCollected = false;
        CollectionDto collectionDto = new CollectionDto();
//        collectionDto.setCompanyId(companyId);
        collectionDto.setGoodsId(goodsId);
        if(collectionService.selectCount(collectionDto) == 1){
            isCollected = true;
        }

        Stock stockDto = new Stock();
        stockDto.setGoodsId(goodsId);
        List<Stock> stockDtoList = stockService.select(stockDto);
        List<Map<String, Object>> goodsStockList = new ArrayList<>();

        for (Stock s:stockDtoList
             ) {
            Map<String, Object> stockMap = new HashMap<>();
            stockMap.put("stockId", s.getStockId());
            stockMap.put("modelMap", JSONObject.parseObject(s.getModelMap()));
            stockMap.put("price", s.getPrice());
            stockMap.put("number", s.getNumber());
            stockMap.put("unit", s.getUnit());
            goodsStockList.add(stockMap);
        }

        goodsDto.setGoodsId(goods.getGoodsId());
        goodsDto.setGoodsName(goods.getGoodsName());
        goodsDto.setShopId(goods.getShopId());
        goodsDto.setShopName(shopUtil.getShopName(goods.getShopId()));
        goodsDto.setCategoryName(categoryUtil.getName(goods.getCategoryId()));
        goodsDto.setIsCollected(isCollected);
        goodsDto.setSoldTimes(goods.getSoldTimes());
        goodsDto.setEvaluatedTimes(goods.getEvaluatedTimes());
        goodsDto.setEvaluate(goods.getEvaluate());
        goodsDto.setGoodsImgUrlList(JSONObject.parseArray(goods.getGoodsImgUrlList(), String.class));
        goodsDto.setGoodsInfoUrlList(JSONObject.parseArray(goods.getGoodsInfoUrlList(), String.class));
        goodsDto.setGoodsAttributeMap(JSONObject.parseObject(goods.getGoodsAttributeMap()));
        goodsDto.setGoodsSpecificationMap(getGoodsSpecificationMap(goodsId));
        goodsDto.setGoodsStockList(goodsStockList);
        return goodsDto;
    }

    public GoodsList selectGoods(Integer goodId,Double minimum){
        Goods goods = getGoodById(goodId);
        GoodsList goodsList = new GoodsList();
        goodsList.setGoodsId(goodId);
        goodsList.setGoodsName(goods.getGoodsName());
        goodsList.setCategoryName(categoryUtil.getName(goods.getCategoryId()));
        goodsList.setGoodsImgUrl(JSONObject.parseArray(goods.getGoodsImgUrlList(), String.class).get(0));
        goodsList.setMinimum(minimum);
        goodsList.setShopId(goods.getShopId());
        goodsList.setEvaluate(goods.getEvaluate());
        goodsList.setSoldTimes(goods.getSoldTimes());
        goodsList.setState(goods.getState());
        goodsList.setShopName(shopUtil.getShopName(goods.getShopId()));

        return goodsList;
    }
    public List<Goods> getMyGoods(GoodsCondition goodsCondition){
        List<Goods> goodsList = new ArrayList<>();
        Integer companyId = goodsCondition.getCompanyId();
        Integer shopId = goodsCondition.getShopId();
        Integer conditionNumber = goodsCondition.getCondition();
        String condition;
        if(conditionNumber.equals(0)) {
            condition = "evaluate";
        }else {
            condition = "sold_times";
        }
        if(shopId.equals(0)){
            goodsList = goodsService.selectByCompanyId(companyId);
        }else {
            goodsList = goodsService.selectByShopId(shopId);
        }

        return goodsList;
    }

    public Goods getGoodById(Integer goodId){
        Goods goods = new Goods();
        goods.setGoodsId(goodId);
        goods = goodsService.selectByPrimaryKey(goods);
        return goods;
    }
    public Goods getGoods(GoodsDto goodsDto){
        Goods goods = new Goods();

        String attribute = JSON.toJSONString(goodsDto.getGoodsAttributeMap());
        String imgUrl = JSON.toJSONString(goodsDto.getGoodsImgUrlList());
        String infoUrl = JSON.toJSONString(goodsDto.getGoodsInfoUrlList());

        goods.setShopId(goodsDto.getShopId());
        goods.setGoodsImgUrlList(imgUrl);
        goods.setGoodsInfoUrlList(infoUrl);
        goods.setGoodsName(goodsDto.getGoodsName());
        goods.setGoodsAttributeMap(attribute);
        goods.setCategoryId(goodsDto.getCategoryId());
        return goods;
    }
    public List<Specification> getSpecification(Map<String, List<Object>> goodsSpecificationList, Integer goodsId){
        List<Specification> specificationList = new ArrayList<>();
        Set<String> entrySet = goodsSpecificationList.keySet();
        for (String name: entrySet
             ) {
            Specification specification = new Specification();
            specification.setSpecificationName(name);
            specification.setGoodsId(goodsId);
            specificationList.add(specification);
        }
        return specificationList;
    }
    public List<Model> getModel(List<Object> goodsModelList, Integer specificationId) {
        List<Model> modelList = new ArrayList<>();
        for (Object name : goodsModelList
        ) {
            Model model = new Model();
            model.setModelName(name.toString());
            model.setSpecificationId(specificationId);
            modelList.add(model);
        }
        return modelList;
    }

    public List<StockDto> getStock(List<Map<String, Object>> goodsStockList){
        List<StockDto> stockList = new ArrayList<>();
        for (Map<String, Object> stockMap:goodsStockList
             ) {
            StockDto stockDto = new StockDto();;
            stockDto.setModelMap(JSON.toJSONString(stockMap.get("modelMap")));
            stockDto.setNumber(Integer.parseInt(stockMap.get("number").toString()));
            stockDto.setUnit(stockMap.get("unit").toString());
            stockDto.setPrice( Double.parseDouble(stockMap.get("price").toString()));
            stockList.add(stockDto);
        }
        return stockList;
    }

    public void updateStockList(List<Stock> stockMapList){
        for (int i = 0; i < stockMapList.size(); i++) {
            Stock stockMap = stockMapList.get(i);
            stockService.updateByPrimaryKeySelective(stockMap);
        }
    }
//public void updateStockList(Map<String,Object> stockMapList){
//    for (int i = 0; i < stockMapList.size(); i++) {
//        Map<String,Object> stockMap = JSONObject.parseObject(JSON.toJSONString(stockMapList.get(i)));
//        stockService.updateByPrimaryKeySelective(getStockInfo(stockMap));
//    }
//}

    public Stock getStockInfo(Map<String,Object> stockMap){
        Stock stock = new Stock();
        String Id = stockMap.get("stockId").toString();
        stock.setStockId(Integer.parseInt(stockMap.get("stockId").toString()));
        stock = stockService.selectOne(stock);
        stock.setNumber(Integer.parseInt(stockMap.get("number").toString()));
        stock.setPrice(Double.parseDouble(stockMap.get("price").toString()));
        stock.setUnit(stockMap.get("unit").toString());
        stock.setModelMap(JSON.toJSONString(stockMap.get("modelMap")));

        return stock;


    }

    public Integer updateStock(Stock stock){
        Integer count = stockService.updateByPrimaryKeySelective(stock);
        return count;
    }

    public void updateState(Goods goods) throws IOException {
        UpdateRequest updateRequest = new UpdateRequest("goods", String.valueOf(goods.getGoodsId()));
        updateRequest.timeout(TimeValue.timeValueSeconds(3));
        UpdateRequest doc = updateRequest.doc(JSON.toJSONString(goods), XContentType.JSON);
        UpdateResponse updateResponse = client.update(doc, RequestOptions.DEFAULT);
        goodsService.updateByPrimaryKeySelective(goods);
    }

    public void updateInfo(GoodsDto goodsDto) throws IOException {
        Goods goods = new Goods();
        goods.setGoodsId(goodsDto.getGoodsId());
        goods.setShopId(goodsDto.getShopId());
        if (goodsDto.getGoodsImgUrlList()!=null){
            goods.setGoodsImgUrlList(JSONObject.toJSONString(goodsDto.getGoodsImgUrlList()));
        }
        if (goodsDto.getGoodsInfoUrlList()!=null){
            goods.setGoodsInfoUrlList(JSONObject.toJSONString(goodsDto.getGoodsInfoUrlList()));
        }
        if (goodsDto.getGoodsAttributeMap()!=null){
            goods.setGoodsAttributeMap(JSONObject.toJSONString(goodsDto.getGoodsAttributeMap()));
        }
        goods.setGoodsName(goodsDto.getGoodsName());
        goods.setCategoryId(goodsDto.getCategoryId());


        UpdateRequest updateRequest = new UpdateRequest("goods", String.valueOf(goodsDto.getGoodsId()));
        updateRequest.timeout(TimeValue.timeValueSeconds(3));
        UpdateRequest doc = updateRequest.doc(JSON.toJSONString(goods), XContentType.JSON);
        UpdateResponse updateResponse = client.update(doc, RequestOptions.DEFAULT);

        goodsService.updateByPrimaryKeySelective(goods);
    }

    public boolean hasGoods(Integer goodsId){
        Goods goods = new Goods();
        goods.setGoodsId(goodsId);
        return goodsService.selectCount(goods) != 0;
    }

    public List<BriefGood> getBriefGood(Integer shopId) {
        Goods goods = new Goods();
        goods.setShopId(shopId);
        List<BriefGood> briefGoodList = new ArrayList<>();
        int count = goodsService.selectCount(goods);
        if (count > 0) {
            List<Goods> goodsList = goodsService.select(goods);
            if (goodsList.size() > 3) {
                for (int i = 0; i < 3; i++) {
                    BriefGood briefGood = getBriefGood(goodsList.get(i));
                    briefGoodList.add(briefGood);
                }
            } else {
                for (Goods value : goodsList) {
                    BriefGood briefGood = getBriefGood(value);
                    briefGoodList.add(briefGood);
                }
            }
        }
        return briefGoodList;
    }
    public BriefGood getBriefGoodById(Integer goodsId){
        Goods goods = getGoodById(goodsId);
        return getBriefGood(goods);
    }
    public BriefGood getBriefGood(Goods goods){
        BriefGood briefGood = new BriefGood();
        briefGood.setGoodsId(goods.getGoodsId());
        briefGood.setGoodsName(goods.getGoodsName());
        briefGood.setGoodsImgUrlList(JSONObject.parseArray(goods.getGoodsImgUrlList(), String.class));

        return briefGood;
    }

    public Integer getNumOfGoods(Integer sellerId){
        int number = 0;
        Goods goods = new Goods();
        ShopDto shop = new ShopDto();
        shop.setCompanyId(sellerId);
        List<ShopDto>  shopList = shopService.select(shop);
        for (ShopDto s: shopList
             ) {
            goods.setShopId(s.getShopId());
            number += goodsService.selectCount(goods);
        }
        return number;
    }

    public BriefGood getBriefGoodByS(Integer stockId){
        Stock stock = new Stock();
        stock.setStockId(stockId);
        stock =stockService.selectByPrimaryKey(stock);
        Integer goodId = stock.getGoodsId();
        Goods goods = getGoodById(goodId);
        BriefGood briefGood = getBriefGood(goods);
        return briefGood;
    }

    public String getGoodNameByS(Integer stockId){
        Stock stock = new Stock();
        stock.setStockId(stockId);
        stock =stockService.selectByPrimaryKey(stock);
        String goodName = getGoodName(stock.getGoodsId());
        return goodName;
    }
    public String getGoodName(Integer goodId){
        Goods goods = new Goods();
        goods.setGoodsId(goodId);
        goods = goodsService.selectByPrimaryKey(goods);
        String goodName = goods.getGoodsName();
        return goodName;
    }

    public GoodsList getGoodsList(Goods goods){
        GoodsList goodsList = new GoodsList();
        goodsList.setGoodsId(goods.getGoodsId());
        goodsList.setGoodsName(goods.getGoodsName());
        goodsList.setGoodsImgUrl(JSONObject.parseArray(goods.getGoodsImgUrlList(), String.class).get(0));
        goodsList.setShopId(goods.getShopId());
        goodsList.setEvaluate(goods.getEvaluate());
        goodsList.setSoldTimes(goods.getSoldTimes());
        goodsList.setState(goods.getState());
        goodsList.setShopName(shopUtil.getShopName(goods.getShopId()));

        return goodsList;
    }
    public List<GoodsList> getBriefGoodsList(){
        List<GoodsList> goodsLists = new ArrayList<>();
        List<Goods> goodsList = goodsService.selectAll();
        int y = goodsList.size();
        if (y > 10){
            y = 10;
        }
        for (int i = 0; i < y; i++) {
            GoodsList good = getGoodsList(goodsList.get(i));

            goodsLists.add(good);
        }

        return goodsLists;
    }
}
